package chat

import (
	"crypto/md5"
	"fmt"
	"github.com/gizak/termui"
	"io"
	"math"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

type SysFileInfo struct {
	fName  string
	fSize  int64
	fMtime time.Time
	fPerm  os.FileMode
	fMd5   string
	fType  bool
}

func writeToFile(data []byte, fileName string, perm os.FileMode) error {
	writeFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, perm)
	if err != nil {
		fmt.Println("write file error:", err)
		return err
	}
	defer writeFile.Close()
	_, err = writeFile.Write(data)
	if err != nil {
		fmt.Println("write file error", err)
		return err
	}
	return nil
}

func Serve() {

	servPort := 12333
	l, err := net.Listen("tcp", ":"+strconv.Itoa(servPort))
	if err != nil {
		fmt.Println("net failed", err)
	}
	err = os.MkdirAll("C:\\tmp\\20150625", 0755)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Start file Service")
	for {
		conn, err := l.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				continue
			}
			fmt.Println("network error", err)
		}
		go handler(conn)
	}
}

func handler(conn net.Conn) {
	defer conn.Close()
	state := 0
	var cmd *SysFileInfo
	var fSize, totalSize int64
	var tempFileName string
	var n int64

	err := termui.Init()
	if err != nil {
		panic(err)
	}
	defer termui.Close()

	termui.UseTheme("helloworld")

	g0 := termui.NewGauge()
	g0.Percent = 0
	g0.Width = 50
	g0.Height = 3
	g0.Border.Label = ""
	g0.BarColor = termui.ColorRed
	g0.Border.FgColor = termui.ColorWhite
	g0.Border.LabelFgColor = termui.ColorCyan

	//	g2 := termui.NewGauge()
	//	g2.Percent = 0
	//	g2.Width = 50
	//	g2.Height = 3
	//	g2.PercentColor = termui.ColorBlue
	//	g2.Y = 3
	//	g2.Border.Label = ""
	//	g2.BarColor = termui.ColorYellow
	//	g2.Border.FgColor = termui.ColorWhite

	//	g1 := termui.NewGauge()
	//	g1.Percent = 0
	//	g1.Width = 50
	//	g1.Height = 5
	//	g1.Y = 6
	//	g1.Border.Label = ""
	//	g1.PercentColor = termui.ColorYellow
	//	g1.BarColor = termui.ColorGreen
	//	g1.Border.FgColor = termui.ColorWhite
	//	g1.Border.LabelFgColor = termui.ColorMagenta

	//	g3 := termui.NewGauge()
	//	g3.Percent = 0
	//	g3.Width = 50
	//	g3.Height = 3
	//	g3.Y = 11
	//	g3.Border.Label = ""
	//	g3.Label = "{{percent}}% (100MBs free)"
	//	g3.LabelAlign = termui.AlignRight

	//<-termui.EventCh()

	for {
		buffer := make([]byte, 2048)
		num, err := conn.Read(buffer)
		numLen := int64(num)
		if err != nil && err != io.EOF {
			fmt.Println("cannot read", err)
		}
		n = 0
		if state == 0 {
			n, cmd = cmdParse(buffer[:num])
			tempFileName = cmd.fName + ".sync"
			fSize = cmd.fSize
			totalSize = fSize
			state = 1
		}
		if state == 1 {
			last := numLen
			if fSize <= numLen-n {
				last = fSize + n
				state = 2
			}
			err = writeToFile(buffer[int(n):int(last)], tempFileName, cmd.fPerm)
			if err != nil {
				fmt.Println("read num error : ", err)
			}
			fSize -= last - n

			//shellExec("clear")
			//fmt.Println("剩余文件大小" + computeFileSize(fSize))

			//fmt.Println(int((float64(fSize) / float64(totalSize)) * 100))

			g0.Percent = int((float64(totalSize-fSize) / float64(totalSize)) * 100)

			if fSize > 0 {
				g0.Border.Label = "剩余：" + computeFileSize(fSize)
			} else {
				g0.Border.Label = "传输完成"
			}
			//			g1.Percent = int((float64(fSize) / float64(totalSize)) * 100)
			//			g1.Border.Label = "剩余：" + computeFileSize(fSize)
			//			g2.Percent = int((float64(fSize) / float64(totalSize)) * 100)
			//			g2.Border.Label = "剩余：" + computeFileSize(fSize)
			//			g3.Percent = int((float64(fSize) / float64(totalSize)) * 100)
			//			g3.Border.Label = "剩余：" + computeFileSize(fSize)

			termui.Render(g0)
			//termui.Render(g0, g1, g2, g3)

			if state == 2 {
				os.Remove(cmd.fName)
				err = os.Rename(tempFileName, cmd.fName)
				if err != nil {
					fmt.Println("rename ", tempFileName, " to ", cmd.fName, " failed")
				}
				err = os.Chtimes(cmd.fName, time.Now(), cmd.fMtime)
				if err != nil {
					fmt.Println("change the mtime error ", err)
				}

				fileHandle, err := os.Open(cmd.fName)
				if err != nil {
					fmt.Println("open ERROR", err)
				}
				h := md5.New()
				io.Copy(h, fileHandle)
				newfMd5 := fmt.Sprintf("%x", h.Sum(nil))
				if newfMd5 == cmd.fMd5 {
					//接收成功
					sendInfo := fmt.Sprintf("%s sync success", cmd.fName)
					conn.Write([]byte(sendInfo))
				} else {
					sendInfo := fmt.Sprintf("%s sync failed", cmd.fName)
					conn.Write([]byte(sendInfo))
				}
			}
		}

	}

}

func cmdParse(infor []byte) (int64, *SysFileInfo) {
	var i int64
	for i = 0; i < int64(len(infor)); i++ {
		if infor[i] == '\n' && infor[i-1] == '\r' {
			cmdLine := strings.Split(string(infor[:i-1]), " ")
			fileName := fmt.Sprintf("%s/%s", "C:\\tmp\\20150625", cmdLine[1])
			filePerm, _ := strconv.Atoi(cmdLine[3])
			fileMtime, _ := strconv.ParseInt(cmdLine[2], 10, 64)
			fileSize, _ := strconv.ParseInt(cmdLine[4], 10, 64)
			fileInfo := &SysFileInfo{
				fName:  fileName,
				fMtime: time.Unix(fileMtime, 0),
				fPerm:  os.FileMode(filePerm),
				fSize:  fileSize,
				fMd5:   string(cmdLine[5]),
			}
			return i + 1, fileInfo
		}
	}
	return 0, nil
}

func computeFileSize(size int64) string {

	if size < 1024 {
		return strconv.FormatInt(size, 10) + "B"
	}
	dic := map[int]string{
		3: "TB",
		2: "MB",
		1: "KB",
	}

	var msg string
	for key, value := range dic {
		if float64(size)/float64(math.Pow(float64(1024), float64(key))) > 1 {
			//两位小数
			msg = strconv.FormatFloat(float64(size)/float64(math.Pow(float64(1024), float64(key))), 'f', 2, 64) + value
			break
		}
	}

	return msg

}

//该代码片段来自于: http://www.sharejs.com/codes/go/5640
